package iptux;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.ServerSocket;
import java.net.Socket;
import baseclass.FileInfo;
import baseclass.PalInfo;

/**
 * Tcp server thread, handles the tcp file send request.
 * @author cwll<cwll2009@126.com>
 *
 */
public class IptuxTCPServer extends Thread{

	//  private String data="";
	private Iptux mainDlg = null;
	//  private String remoteAddress = null;
	public String localhost;
	byte[] buffer = new byte[1024];
	ServerSocket svrSocket;
	
	public IptuxTCPServer(String localhost,Iptux maindlg){
		this.mainDlg = maindlg;
		this.localhost = localhost;
		try {
			svrSocket = new ServerSocket(StaticConsts.IPMSG_PORT,1024,InetAddress.getByName(this.localhost));
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
    /**
     * Get the IP address of the UDP server.
     * @return localhost is a string of IP address
     */
    public String getServerIP(){
    	return localhost;
    }
    
    @Override
	public void run(){
		//int readBytes = -1;
		try {
			Socket socket = null;
			while ((socket = svrSocket.accept()) != null) {
				new Thread(new TCPFileSenderThread (socket)).start(); 
				this.mainDlg.appendClientSocket(socket);
			}
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			System.out.println("error receive tcp");
		}
	}
    
    /**
     * File send thread.
     * @author cwll<cwll2009@126.com>
     *
     */
    class TCPFileSenderThread implements Runnable{

		Socket socket;
		InputStream StreamIn;
		OutputStream Streamout;
		FileInfo fileInfo;
		
		public TCPFileSenderThread(Socket socket) {
			this.socket = socket;
		}

		@Override
		public void run() {
			try {
				while (true) {
					byte[] buff = new byte[1024];
					StreamIn = this.socket.getInputStream();
					//isr = new InputStreamReader(StreamIn);
					int readBytes = StreamIn.read(buff, 0, buff.length);
					//int readBytes = isr.read(buff, 0, buff.length);
					if (readBytes == -1) {
						return;
					}
					String data = new String(buff);
					//System.out.print(data);
					if (data.split(":").length < 5){
						return;
					}
					int commandno = Integer.valueOf(data.split(":")[4]);
					commandno = StaticConsts.GET_MODE(commandno);
					if (commandno == StaticConsts.IPMSG_GETFILEDATA)  {
						//System.out.println("someone get file data");
						this.parseRequestData(data, socket);
					} else if (commandno == StaticConsts.IPMSG_GETDIRFILES) {
						//System.out.println("someone get dir files");
						this.parseRequestData(data,socket);
						
					} else if (commandno == StaticConsts.IPTUX_SENDSUBLAYER) {
						System.out.println("someone get get sublayer");
					} /*else {
						continue;
					}*/
					//isr.close();
				}
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("error receive tcp");
			}
		}
		
		/**
		 * Parse the file request tcp data 
		 * @param data the data converted to string
		 * @param socket the socket accept the client request.
		 */
		public void parseRequestData(String data,Socket socket){
	        int commandno = Integer.valueOf(data.split(":")[4]);
	        commandno = StaticConsts.GET_MODE(commandno);
			//String[] tmp = data.split(":");
			String[] attach = new String[data.split(":").length - 5];
			for(int i = 0; i <  data.split(":").length -5; i++){
				attach[i] =  data.split(":")[i + 5] ;
			}
			//packetID:fileID: offset  are all hex
			int fileid = Integer.valueOf(attach[1],16);
			//long packetn = Long.valueOf(attach[0],16);
			long packetn = Long.valueOf(attach[0],16);
			long fileOffset;
			//System.out.println("attach[2] is : " + attach[2]);
	        if (attach[2].trim().equals("")){
	            fileOffset = 0;
	        }else{
	        	fileOffset = Integer.valueOf(attach[2],16);
	        }
			fileInfo = mainDlg.findSendFile(packetn,fileid);
			if(fileInfo == null){
				System.out.println("Can't find the request file with fileID:" + fileid + "packetn:" + packetn);
				return;
			}
			String clientIP = socket.getInetAddress().getHostAddress();
			PalInfo pal = mainDlg.findPal(clientIP);
			if(pal == null){
				System.out.println("Can't find pal");
				return;
			}
			if (commandno == StaticConsts.IPMSG_GETFILEDATA){
				RegularFileSender(pal,fileInfo,fileOffset);
	        }else if (commandno == StaticConsts.IPMSG_GETDIRFILES) {
	        	try {
					DirFileSender(pal,fileInfo);
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
	        }
			DialogPeer dlgPeer = mainDlg.findDialogPeer(clientIP);
			if(dlgPeer != null){
				dlgPeer.fileSendCompleteHint(fileInfo);
			}
		}
		
		/**
		 * Method to send regular file.
		 * @param pal PalInfo object of pal.
		 * @param fileInfo FileInfo object of file to send.
		 * @param fileOffset the offset to start send  with
		 */
	    public void RegularFileSender(PalInfo pal,FileInfo fileInfo,long fileOffset){
	    	try {
				File file = new File(fileInfo.filepath);
				FileInputStream fInputStream = new FileInputStream(file);
				Streamout = this.socket.getOutputStream();
				byte[] bufFile = new byte[1024];
				int readBytes = 0;
				fInputStream.skip(fileOffset);
				while (true) {
					readBytes = fInputStream.read(bufFile, 0, bufFile.length);
					if (readBytes == -1) {
						break;
					}
					Streamout.write(bufFile, 0, readBytes);
					fileInfo.transmittedSize = fileInfo.transmittedSize + readBytes;
				}
				fInputStream.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				System.out.println("error receive tcp");
			}
	    }
	    
		/**
		 * Method to send directory.
		 * @param pal PalInfo object of pal.
		 * @param fileInfo FileInfo object of file to send.
		 */
	    public void DirFileSender(PalInfo pal,FileInfo fileInfo) throws IOException {
			Streamout = socket.getOutputStream();
	    	traverseFolder(pal,fileInfo.filepath);
	    	//When send the top folder over, send a signal to parent to tell the pal to exit
	    	//receive thread.
	    	buffer = Utils.makeFileSendStreamHeader(null,mainDlg.configer.msgEncoding);
	    	Streamout.write(buffer, 0, buffer.length);
	    	//System.out.println("exit to parent, current is :" +  fileInfo.filepath);
	    	//System.out.println("send :" + buffer);
	    	
	    	DialogPeer dialogPeer = mainDlg.findDialogPeer(pal.ipv4);
	    	if(dialogPeer != null){
	    		dialogPeer.removeFileFromTable(dialogPeer.table_FileToSend,this.fileInfo,4);
	    		dialogPeer.sendFileList.remove(this.fileInfo);
	    	}
	    }
	    
	    /**
	     * walks recursively of the folder, send folder structure and file content to pal.
	     * @param pal PalInfo object of pal.
	     * @param path path of folder to send.
	     * @throws IOException
	     */
		public void traverseFolder(PalInfo pal,String path) throws IOException {
			byte[] bufFile = new byte[1024];
			byte[] buffer;
			
			File file = new File(path);
			if (file.exists()) {
				buffer = Utils.makeFileSendStreamHeader(file.getPath(),mainDlg.configer.msgEncoding);
		    	Streamout.write(buffer, 0, buffer.length);
				
				File[] files = file.listFiles();
				if (files.length == 0) {
					//System.out.println("文件夹是空的!");
					return;
				} else {
					for (File file2 : files) {
						if (file2.isDirectory()) {
							//System.out.println("文件夹:" + file2.getAbsolutePath());
							traverseFolder(pal,file2.getAbsolutePath());
							//send a folder over, exit to parent
							buffer = Utils.makeFileSendStreamHeader(null,mainDlg.configer.msgEncoding);
					    	Streamout.write(buffer, 0, buffer.length);
					    	//System.out.println("exit to parent, current is :" +  file2.getPath());
					    	//System.out.println("send :" + buffer);
					    	
						} else {
							//System.out.println("文件:" + file2.getAbsolutePath());
							buffer = Utils.makeFileSendStreamHeader(file2.getPath(),mainDlg.configer.msgEncoding);
					    	Streamout.write(buffer, 0, buffer.length);
							int readBytes = 0;
							InputStream fInputStream = new FileInputStream(file2);
							while (true) {
								readBytes = fInputStream.read(bufFile, 0, bufFile.length);
								if (readBytes <= 0) {
									break;
								}
								Streamout.write(bufFile, 0, readBytes);
								this.fileInfo.transmittedSize  = fileInfo.transmittedSize + readBytes;
							}
							fInputStream.close();
						}
					}
				}
			} else {
				System.out.println("File not exist!");
			}

		}
    }
 
}
